package com.longlong.orm;

import com.longlong.pool.BusinessException;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author longlong
 */
public class Handler {

    /**
     * 解析 SQL 语句
     * 解析前：update student set name=#{sname},age=#{sage},class_id=#{classId} where id=#{id}
     * 解析后：update student set name=?,age=?,class_id=? where id=?
     *
     * @param sql sql语句
     * @return 解析后的 SQL 和 key 列表
     */
    SqlAndKey parseSql(String sql) {
        StringBuilder newSql = new StringBuilder();
        List<String> keyList = new ArrayList<>();
        // 解析 SQL
        while (true) {
            int index = sql.indexOf("#{");
            if (index == -1) {
                newSql.append(sql);
                break;
            }
            newSql.append(sql.substring(0, index));
            sql = sql.substring(index + 2);
            int endIndex = sql.indexOf("}");
            String key = sql.substring(0, endIndex);
            keyList.add(key);
            newSql.append("?");
            sql = sql.substring(endIndex + 1);
        }
        return new SqlAndKey(newSql, keyList);
    }

    /**
     * 从 obj 对象中取数据
     * 给 pstate 填充参数
     *
     * @param pstate  PreparedStatement
     * @param obj     要设置参数的对象
     * @param keyList 参数列表
     * @throws SQLException 异常
     */
    void handleParameter(PreparedStatement pstate, Object obj, List<String> keyList) throws SQLException {
        // 获取 obj 类型
        Class<?> clazz = obj.getClass();
        switch (clazz.getName()) {
            case "int", "java.lang.Integer" -> pstate.setInt(1, (Integer) obj);
            case "long", "java.lang.Long" -> pstate.setLong(1, (Long) obj);
            case "float", "java.lang.Float" -> pstate.setFloat(1, (Float) obj);
            case "double", "java.lang.Double" -> pstate.setDouble(1, (Double) obj);
            case "java.lang.String" -> pstate.setString(1, (String) obj);
            default -> {
                if (clazz.isArray()) {
                    throw new BusinessException("数组类型暂不支持");
                } else if (obj instanceof Map) {
                    this.setMap(pstate, obj, keyList);
                } else {
                    this.setObject(pstate, obj, keyList);
                }
            }
        }
    }

    /**
     * 从 ResultSet 中获取数据
     * 将数据转化为返回类型
     *
     * @param rs         结果集
     * @param resultType 返回类型
     * @return 返回对象对应的对象
     * @throws SQLException 异常
     */
    Object handleResult(ResultSet rs, Class<?> resultType) throws SQLException {
        Object result;
        switch (resultType.getName()) {
            case "int", "java.lang.Integer" -> result = rs.getInt(1);
            case "long", "java.lang.Long" -> result = rs.getLong(1);
            case "float", "java.lang.Float" -> result = rs.getFloat(1);
            case "double", "java.lang.Double" -> result = rs.getDouble(1);
            case "java.lang.String" -> result = rs.getString(1);
            case "java.util.Map" -> result = this.getMap(rs);
            default -> result = this.getObject(rs, resultType);
        }
        return result;
    }


    // ========== private method ==========

    private void setMap(PreparedStatement pstat, Object obj, List<String> keyList) throws SQLException {
        Map map = (Map) obj;
        for (int i = 0; i < keyList.size(); i++) {
            pstat.setObject(i + 1, map.get(keyList.get(i)));
        }
    }

    private void setObject(PreparedStatement pstat, Object obj, List<String> keyList) {
        try {
            Class<?> clazz = obj.getClass();
            for (int i = 0; i < keyList.size(); i++) {
                String key = keyList.get(i);
                //通过反射 找到 obj 对象中 key 属性
                Field field = clazz.getDeclaredField(key);
                field.setAccessible(true);
                pstat.setObject(i + 1, field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Map<String, Object> getMap(ResultSet rs) throws SQLException {
        // 创建map
        Map<String, Object> result = new HashMap<>(10);
        // 获取结果集中的全部信息
        ResultSetMetaData resultSetMetaData = rs.getMetaData();
        // 遍历结果集中的全部列
        for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
            // 获取每一个列名字
            String columnName = resultSetMetaData.getColumnName(i);
            // 根据每一个列名 获取值
            Object value = rs.getObject(columnName);
            //存入map中
            result.put(columnName, value);
        }
        return result;
    }

    private Object getObject(ResultSet rs, Class<?> resultType) throws SQLException {
        Object obj = null;
        try {
            // 通过反射创建对象
            obj = resultType.newInstance();
            // 获取结果集中的全部信息
            ResultSetMetaData resultSetMetaData = rs.getMetaData();
            // 遍历循环结果集
            for (int i = 1; i < resultSetMetaData.getColumnCount() + 1; i++) {
                // 获取结果集的每一个列名字
                String columnName = resultSetMetaData.getColumnName(i);
                // 反射找到列名字对应的那个属性
                Field field = resultType.getDeclaredField(columnName);
                // 操作私有属性
                field.setAccessible(true);
                // 给属性赋值
                field.set(obj, rs.getObject(columnName));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


}
